/**
 *******************************************************************************
 * @FileName  : hci_tr_port.c
 * @Author    : GaoQiu
 * @CreateDate: 2020-09-10
 * @Copyright : Copyright(C) GaoQiu
 *              All Rights Reserved.
 *
 *******************************************************************************
 *
 * The information contained herein is confidential and proprietary property of
 * GaoQiu and is available under the terms of Commercial License Agreement
 * between GaoQiu and the licensee in separate contract or the terms desc ribed
 * here-in.
 *
 * This heading MUST NOT be removed from this file.
 *
 * Licensees are granted free, non-transferable use of the information in this
 * file under Mutual Non-Disclosure Agreement. NO WARRENTY of ANY KIND is provided.
 *
 *******************************************************************************
 */
#include "hci_tr_port.h"
#include "hci_tr_api.h"

#include "bsp/bsp.h"

#include "utils/track.h"

#include "platform/platform.h"

uint8_t A_uartTxDMAChnId = 0;
uint8_t A_uartRxDMAChnId = 0;

void HCI_TR_UartInit(uint8_t *pRxBuf, uint32_t byteSize)
{
#if defined(IP_108)
    CLK_APB2PeriphClockCmd(CLK_APB2Periph_UART1, ENABLE);
    CLK_AHBPeriphClockCmd(CLK_AHBPeriph_DMAC, ENABLE);

    // UART
    GPIO_EnableDigitalPath(P0, BIT6);
    GPIO_EnableDigitalPath(P0, BIT7);
    GPIO_SetMode(P0, BIT(6), GPIO_MODE_OUTPUT);
    GPIO_SetMode(P0, BIT(7), GPIO_MODE_OUTPUT);
    SYS_SET_MFP(P0, 6, UART1_TX);
    SYS_SET_MFP(P0, 7, UART1_RX);

#elif defined(IP_107)
    CLK_APB2PeriphClockCmd(CLK_APB2Periph_UART1, ENABLE);
    CLK_AHBPeriphClockCmd(CLK_AHBPeriph_DMAC, ENABLE);

    // UART Pin Config
  #ifdef PAN107x_DK // 40pin
	GPIO_EnableDigitalPath(P3, BIT1);
	GPIO_EnableDigitalPath(P3, BIT0);
	GPIO_SetMode(P3, BIT(1), GPIO_MODE_OUTPUT);
	GPIO_SetMode(P3, BIT(0), GPIO_MODE_OUTPUT);
	SYS_SET_MFP(P3, 1, UART1_TX);
	SYS_SET_MFP(P3, 0, UART1_RX);
  #elif defined(PAN107x_DK_32) // 32pin
	GPIO_EnableDigitalPath(P0, BIT7);
	GPIO_EnableDigitalPath(P1, BIT0);
	GPIO_SetMode(P0, BIT(7), GPIO_MODE_OUTPUT);
	GPIO_SetMode(P1, BIT(0), GPIO_MODE_OUTPUT);
	SYS_SET_MFP(P1, 0, UART1_TX);
	SYS_SET_MFP(P0, 7, UART1_RX);
  #endif
#endif

	// UART Config
    UART_InitTypeDef uartInit;
    uartInit.UART_BaudRate = HCI_TR_BAUDRATE;
    uartInit.UART_LineCtrl = Uart_Line_8n1;
    UART_Init(HCI_TR_UART_ID, &uartInit);

    UART_EnableFifo(HCI_TR_UART_ID); //ENABLE FIFO mode
    //UART_DisableFifo(HCI_TR_UART_ID);

    UART_EnableIrq(HCI_TR_UART_ID, UART_IRQ_RECV_DATA_AVL);
    NVIC_EnableIRQ(HCI_TR_UART_IRQn);

    /* DMA init. */
    //Tx
    DMAC_ChannelConfigTypeDef tx_cfg = {0};
    tx_cfg.AddrChangeDst   = DMAC_AddrChange_NoChange;
    tx_cfg.AddrChangeSrc   = DMAC_AddrChange_Increment;
    tx_cfg.BurstLenDst     = DMAC_BurstLen_1;
    tx_cfg.BurstLenSrc     = DMAC_BurstLen_1;
    tx_cfg.DataWidthDst    = DMAC_DataWidth_8; //8bits
    tx_cfg.DataWidthSrc    = DMAC_DataWidth_8; //8bits
    tx_cfg.TransferType    = DMAC_TransferType_Mem2Per;
    tx_cfg.FlowControl     = DMAC_FlowControl_DMA;
    tx_cfg.HandshakeDst    = DMAC_Handshake_Hardware;
    tx_cfg.HandshakeSrc    = DMAC_Handshake_Hardware;
    tx_cfg.PeripheralDst   = HCI_TR_UART_DMA_TX;
    tx_cfg.IntEnable       = ENABLE;

    //Rx
#if 0
    DMAC_ChannelConfigTypeDef rx_cfg = {0};
    rx_cfg.AddrChangeDst   = DMAC_AddrChange_Increment;
    rx_cfg.AddrChangeSrc   = DMAC_AddrChange_NoChange;
    rx_cfg.BurstLenDst     = DMAC_BurstLen_1;
    rx_cfg.BurstLenSrc     = DMAC_BurstLen_1;
    rx_cfg.DataWidthDst    = DMAC_DataWidth_8; //8bits
    rx_cfg.DataWidthSrc    = DMAC_DataWidth_8; //8bits
    rx_cfg.TransferType    = DMAC_TransferType_Per2Mem;
    rx_cfg.FlowControl     = DMAC_FlowControl_DMA;
    rx_cfg.HandshakeDst    = DMAC_Handshake_Hardware;
    rx_cfg.HandshakeSrc    = DMAC_Handshake_Hardware;
    rx_cfg.PeripheralSrc   = HCI_TR_UART_DMA_RX;
    rx_cfg.IntEnable       = ENABLE;
#endif

    DMAC_Init(DMA);

    A_uartTxDMAChnId = DMAC_AcquireChannel(DMA);
    //DMAC_ClrIntFlagMsk(DMA, A_uartTxDMAChnId, DMAC_FLAG_INDEX_TFR);
    DMAC_SetChannelConfig(DMA, A_uartTxDMAChnId, &tx_cfg);

#if 0
    A_uartRxDMAChnId = DMAC_AcquireChannel(DMA);
    DMAC_ClrIntFlagMsk(DMA, A_uartRxDMAChnId, DMAC_FLAG_INDEX_TFR);
    DMAC_SetChannelConfig(DMA, A_uartRxDMAChnId, &rx_cfg);

    extern void UART_StartRx(uint8_t *pRxBuf, uint32_t size);
    UART_StartRx(pRxBuf, byteSize);
#else
    UART_SetRxTrigger(HCI_TR_UART_ID, UART_RX_FIFO_HALF_FULL);
#endif

    NVIC_EnableIRQ(DMA_IRQn);
}

uint8_t HCI_TR_Received(void)
{
	return UART_ReceiveData(HCI_TR_UART_ID);
}

uint8_t HCI_TR_UartSendDataByDma(uint8_t *pdata, uint32_t size)
{
	DMAC_StartChannel(DMA, A_uartTxDMAChnId, pdata, (void*)&(HCI_TR_UART_ID->RBR_THR_DLL), size);
	return 1;
}

void HCI_TR_UartStartRx(uint8_t *pRxBuf, uint32_t size)
{
	DMAC_StartChannel(DMA, A_uartRxDMAChnId, (void*)&(HCI_TR_UART_ID->RBR_THR_DLL), pRxBuf, size);
}

bool_t HCI_TR_IsUartBusy(void)
{
	return (UART_GetLineStatus(HCI_TR_UART_ID) & UART_LINE_TXSR_EMPTY) ? false:true;
}

void HCI_TR_UartTxIrq(void)
{
	 if(DMAC_IntFlag(DMA, A_uartTxDMAChnId, DMAC_FLAG_INDEX_TFR))
	 {
		 DMAC_ClrIntFlag(DMA, A_uartTxDMAChnId, DMAC_FLAG_INDEX_TFR);
	 }
}

#if UART_TEST_EN
uint8_t A_rxBuf[128];
uint8_t A_cnt = 0;

void HCI_TR_UartTestInit(void)
{
	HCI_TR_UartInit(A_rxBuf, sizeof(A_rxBuf));
}

void UART_IRQHandler(void)
{
	if(UART_GetLineStatus(HCI_TR_UART_ID) & UART_LINE_DATA_RDY)
	{
		uint32_t rxNum = UART_GetRxFifoLevel(HCI_TR_UART_ID);

		for(int i=0; i<rxNum; i++){
			uint8_t data = UART_ReceiveData(HCI_TR_UART_ID);
			A_rxBuf[A_cnt++] = data;
			UART_SendData(HCI_TR_UART_ID, data);
		}

		HCI_TR_TRACK_ERR("uart irq\r\n");
		HCI_TRACK_DATA(A_rxBuf, A_cnt);
		A_cnt = 0;
	}
}

void DMA_IRQHandler(void)
{
	if(DMAC_CombinedIntStatus(DMA, DMAC_FLAG_MASK_TFR))
	{
		HCI_TR_TRACK_INFO("DMA IRQ\r\n");

		 // DMA TX
		 if(DMAC_IntFlag(DMA, A_uartTxDMAChnId, DMAC_FLAG_INDEX_TFR))
		 {
			 DMAC_ClrIntFlag(DMA, A_uartTxDMAChnId, DMAC_FLAG_INDEX_TFR);

			 HCI_TR_TRACK_INFO("UART TX IRQ\r\n");
		 }

		 // DMA RX
		 if(DMAC_IntFlag(DMA, A_uartRxDMAChnId, DMAC_FLAG_INDEX_TFR))
		 {
			 DMAC_ClrIntFlag(DMA, A_uartRxDMAChnId, DMAC_FLAG_INDEX_TFR);

			 HCI_TR_UartStartRx(A_rxBuf, sizeof(A_rxBuf));
			// UART_SendDataByDma(A_rxBuf, sizeof(A_rxBuf));

			 HCI_TR_TRACK_INFO("UART RX IRQ\r\n");
		 }
	}
}

#endif

